package com.cea.papyrus.diagram.composite.editpart;

import java.util.Iterator;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.InstanceValue;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.LiteralUnlimitedNatural;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.StructuralFeature;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.ValueSpecification;

import com.cea.papyrus.core.editor.ModelManager;
import com.cea.papyrus.core.editpart.ContainerHighlightEditPolicy;
import com.cea.papyrus.core.editpart.ContainerWithSemanticEditPart;
import com.cea.papyrus.diagram.composite.figure.ClassFigure;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

public class CompositeSlotEditPart extends ContainerWithSemanticEditPart {


	public CompositeSlotEditPart(GraphNode graphNode,ModelManager modelManager) {
		super(graphNode,modelManager);
	}


	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.editpart.ContainerWithSemanticEditPart#createEditPolicies()
	 */
	@Override
	protected void createEditPolicies() {
		super.createEditPolicies();
        // overload the GRAPHICAL_NODE_ROLE editPolicy to use the diagram specific one
        installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new GraphNodeEditPolicy() );
        // other editPolicies
		installEditPolicy(EditPolicy.SELECTION_FEEDBACK_ROLE,
				new ContainerHighlightEditPolicy());// Does not run?!!
		if(getContentPane() != null) {
			installEditPolicy(EditPolicy.LAYOUT_ROLE, new CompositeLayoutEditPolicy(
					(XYLayout) getContentPane().getLayoutManager()));
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getContentPane()
	 */
	@Override
	public IFigure getContentPane() {
		IFigure fig = getFigure();
		if(fig instanceof ClassFigure) {
			return ((ClassFigure)fig).getContentsPane();
		}
		return null;
	}
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.editpart.GraphNodeWithSemanticEditPart#createFigure()
	 */
	@Override
	protected IFigure createFigure() {
		// Try to get figure from ContainerWithSemanticEditPart
		IFigure fig = super.createFigure();
		if (fig != null) {
			return fig;
		}
		return new ClassFigure();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.editpart.GraphNodeWithSemanticEditPart#getUmlElement()
	 */
	@Override
	public Slot getUmlElement() {
		Element e=((Uml1SemanticModelBridge)getGraphNode().getSemanticModel()).getElement();
		// case of element import
		if(e instanceof ElementImport){
			return (org.eclipse.uml2.uml.Slot)((ElementImport) e).getImportedElement();
		}
		// this is a simple Slot
		return (org.eclipse.uml2.uml.Slot)e;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.common.editpart.GraphNodeWithSemanticEditPart#refreshVisuals()
	 */
	@Override
	protected void refreshVisuals() {

		Dimension size = getGraphNode().getSize();
		Point p = getGraphNode().getPosition();
		Rectangle r = new Rectangle(p ,size);
//		set colors


		IFigure fig = getFigure();
		if(fig instanceof ClassFigure) {

			ClassFigure f = (ClassFigure)fig;
			f.refreshColors(getGraphNode());
			StructuralFeature definingFeature = getUmlElement().getDefiningFeature();
			String name;
			if(definingFeature==null)
				name="UndefinedSlot";
			else {
				if(!( definingFeature.getType() instanceof PrimitiveType)){
					String valuesLabel = getLabels((Slot)getUmlElement(),false);
					name = valuesLabel+"/"+definingFeature.getName()+":"+definingFeature.getType().getLabel();
					f.setContainer(true);
					f.setNameUnderlined(true);
				}
				else{
					String valuesLabel = getLabels((Slot)getUmlElement(),true);
					name = definingFeature.getName()+" = "+valuesLabel;
					f.setContainer(false);
					f.setNameUnderlined(false);
					
				}
			}
			f.setName(name);//set the name
			//f.setSlot();

		}
		((GraphicalEditPart) getParent()).setLayoutConstraint(
				this,
				fig,
				r);
	}
	
	/**
	 * Returns a label for this composite slot
	 * @param slot the slot for which the label is calculated
	 * @param braket boolean set to <code>true</code> if brakets must be added
	 * to the bounds of the label
	 * @return a label for this slot
	 */
	protected String getLabels(Slot slot, boolean braket){
		String result = "";
 
		// if no value: return
		if(slot.getValues().isEmpty())
			return result;

		// defining feature is multivalued
		if(slot.getDefiningFeature().isMultivalued()){
			Iterator<ValueSpecification> valueSpecs = slot.getValues().iterator();

			if( braket){
				result+="[";
			}
			else
			{result+="";}
			while(valueSpecs.hasNext()){
				ValueSpecification currentValueSpec = valueSpecs.next();
				result+=getLabel(currentValueSpec)+", ";
			}

			result=result.substring(0, result.length()-2)+"";
			if(braket){
				result=result+"]";
			}
		}

		// defining feature is monovalued
		else {
			result+=getLabel((ValueSpecification)slot.getValues().get(0));
		}

		return result;
	}

	/**
	 * Returns a label for the given Value Specification
	 * @param valueSpecification the ValueSpecification for which the label is calculated
	 * @return the label corresponding to this ValueSpecification
	 */
	protected String getLabel(ValueSpecification valueSpecification){
		String label="";

		Type type = ((Slot)getUmlElement()).getDefiningFeature().getType();
		String typeName = type.getName();

		if(type instanceof PrimitiveType){
			if(typeName.equals("Integer")){
				if(valueSpecification instanceof LiteralInteger) {
					label += String.valueOf(((LiteralInteger)valueSpecification).getValue());
				}
			} else if(typeName.equals("UnlimitedNatural")){
				if(valueSpecification instanceof LiteralUnlimitedNatural) {
					label += String.valueOf(((LiteralUnlimitedNatural)valueSpecification).getValue());
				}
			} else if(typeName.equals("String")){
				if(valueSpecification instanceof LiteralString) {
					label += ((LiteralString)valueSpecification).getValue();
				}
			} else if(typeName.equals("Boolean")){
				if(valueSpecification instanceof LiteralBoolean) {
					label += String.valueOf(((LiteralBoolean)valueSpecification).isValue());
				}
			}
		}

		// InstanceValue
		else if(type instanceof Classifier){
			if(valueSpecification instanceof InstanceValue) {
				InstanceSpecification is = ((InstanceValue)valueSpecification).getInstance();
				if(is!=null) {
					label += is.getLabel();
				}
			}
			
		}

		return label;
	}

}
